package com.ctshk.rpc.ship.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.CurrencyRateExchangeConstant;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.DateUtil;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.common.utils.process.ProcessorUtil;
import com.ctshk.rpc.ship.constant.ShipConstant;
import com.ctshk.rpc.ship.dto.*;
import com.ctshk.rpc.ship.entity.*;
import com.ctshk.rpc.ship.mapper.*;
import com.ctshk.rpc.ship.req.*;
import com.ctshk.rpc.ship.service.IShipProductService;
import com.ctshk.rpc.ship.service.IShipRouteService;
import com.ctshk.rpc.ship.service.ZJShipProductService;
import com.ctshk.rpc.system.dto.SysAgentQueryListDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.req.SysAgentQueryListReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.CollectionUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 船票产品 服务实现类
 * </p>
 *
 * @author 谢诗宏
 * @since 2021-03-05
 */
@Slf4j
@DubboService
public class ShipProductServiceImpl extends ServiceImpl<ShipProductMapper, ShipProduct> implements IShipProductService {

    @Autowired
    private ShipProductMapper shipProductMapper;

    @Autowired
    private ShipProductCostMapper shipProductCostMapper;

    @Autowired
    private ShipProductCostDateMapper shipProductCostDateMapper;

    @Autowired
    private ShipProductReservationSettingsMapper shipProductReservationSettingsMapper;

    @Autowired
    private ShipProductCostTouristMapper shipProductCostTouristMapper;

    @Autowired
    private ShipProductChannelOfflineSelfCustomMapper shipProductChannelOfflineSelfCustomMapper;

    @Autowired
    private ShipInitializationSettingsMapper shipInitializationSettingsMapper;

    @DubboReference
    ISysUserService sysUserService;

    @DubboReference
    ISysDepartmentService iSysDepartmentService;

    @DubboReference
    ZJShipProductService zJShipProductService;

    @DubboReference
    private IShipRouteService iShipRouteService;

    @DubboReference
    private ISysApprovalService iSysApprovalService;

    //汇率服务
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;
    @DubboReference
    private ISysAgentService sysAgentService;
    @DubboReference
    private ISysPermissionService sysPermissionService;
    @Autowired
    private ShipProductSaleRecordMapper shipProductSaleRecordMapper;

    @Override
    public Result<ShipProductUpdateApiSettingDTO> queryApiSetting(Long id) {
        ShipProductUpdateApiSettingDTO shipProductUpdateApiSettingDTO = new ShipProductUpdateApiSettingDTO();
        shipProductUpdateApiSettingDTO.setId(id.toString());
        ShipProduct shipProduct = shipProductMapper.selectOne(new QueryWrapper<ShipProduct>().lambda().eq(ShipProduct::getId, id));
        shipProductUpdateApiSettingDTO.setPackStatus(shipProduct.getPackStatus());
        shipProductUpdateApiSettingDTO.setChargeUserId(shipProduct.getChargeUserId());
        shipProductUpdateApiSettingDTO.setChargeUser(shipProduct.getChargeUserName());

        ShipProductReservationSettings shipProductReservationSettings = shipProductReservationSettingsMapper.selectOne(
                new QueryWrapper<ShipProductReservationSettings>().lambda().eq(ShipProductReservationSettings::getShipProductId, id));
        shipProductUpdateApiSettingDTO.setBookingPriceType(shipProductReservationSettings.getServiceChargeType());
        shipProductUpdateApiSettingDTO.setBookingPrice(shipProductReservationSettings.getServiceChargePrice());
        shipProductUpdateApiSettingDTO.setRefundFeePriceType(shipProductReservationSettings.getRefundFeeType());
        shipProductUpdateApiSettingDTO.setRefundFeePrice(shipProductReservationSettings.getRefundFeePrice());

        return Result.success(shipProductUpdateApiSettingDTO);
    }

    @Override
    public Result update(ShipProductReq shipProductReq, TokenUser user) {
        if(shipProductReq.getApprovalStatus() == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11043);
        }
        switch (shipProductReq.getApprovalStatus()){
            //未提交审核、审核不通过，编辑，方案：先删除后增
            case 1:
            case 4:
                return updateUnapprovedShipProduct(shipProductReq,user);
            //审核通过  分: 1手动产品 ,2 API产品编辑
            case 5:
                if(shipProductReq.getProductSource() == 1){
                    return updateApprovedXDShipProduct(shipProductReq,user);
                }
                if(shipProductReq.getProductSource() == 2){
                    return updateApprovedZJShipProduct(shipProductReq,user);
                }
                break;
            default:
                break;
        }
        return Result.success(shipProductReq.getId());
    }

    @Override
    public PageResponse<ShipProductDTO> queryShipList(ShipProductPageReq shipProductPageReq) {
        PageResponse<ShipProductDTO> result = null;
        IPage<ShipProductDTO> agentPage = new Page<>(shipProductPageReq.getPageNo(), shipProductPageReq.getPageSize());
        agentPage = shipProductMapper.queryShipList(shipProductPageReq, agentPage);
        List<ShipProductDTO> records = agentPage.getRecords();
        ProcessorUtil.processMore(records,ShipProductDTO.class);
        result = new PageResponse<>(records, agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    @Override
    public List<ShipProductDTO> queryShipList2(ShipProductPageReq shipProductPageReq) {
        return shipProductMapper.queryShipList(shipProductPageReq);
    }

    @Override
    public Result<Long> check(ShipProductCheckReq shipProductCheckReq, TokenUser currentUser) {
        Result<ApprovalCheckDTO> result = iSysApprovalService.check(shipProductCheckReq.getId(),currentUser.getId(),shipProductCheckReq.getStatus(),null);
        if(result.isSuccess()){
            if(result.getData().getIsFinish()){
                ShipProduct localFunProduct = baseMapper.selectById(shipProductCheckReq.getProductId());
                localFunProduct.setModifiedId(currentUser.getId());
                localFunProduct.setGmtModified(LocalDateTime.now());
                if(shipProductCheckReq.getStatus() == 3){
                    //审批通过
                    localFunProduct.setSellStatus(1);
                }
                localFunProduct.setApprovalStatus(shipProductCheckReq.getStatus());
                baseMapper.updateById(localFunProduct);
            }
        }else {
            Result result1 = new Result();
            result1.setCode(result.getCode());
            result1.setMsg(result.getMsg());
            return result1;
        }
        return Result.success(shipProductCheckReq.getId());
    }


    /**
     * 查询预订中心-产品列表
     * gzl-wansi001
     * @param shipProductSearchReq
     * @param user
     * @return
     */
    @Override
    public ReserveShipProductDto queryReserveNewList(ShipProductSearchReq shipProductSearchReq, TokenUser user) {
        if(shipProductSearchReq.getCompanyType() == null){
            return queryComposeShipReserve(shipProductSearchReq,user);
        }
        switch (shipProductSearchReq.getCompanyType()){
            //信德
            case ShipConstant.MANUAL_COMPANY_TYPE:
                return queryLocalShipReserve(shipProductSearchReq,user);
            //珠江 API产品
            case ShipConstant.API_COMPANY_TYPE:
                return queryPearlRiverShipReserve(shipProductSearchReq,user);
            default:
                return queryComposeShipReserve(shipProductSearchReq,user);
        }
    }

    /**
     * 获取组合产品
     * @param shipProductSearchReq
     * @param user
     * @return
     */
    private ReserveShipProductDto queryComposeShipReserve(ShipProductSearchReq shipProductSearchReq, TokenUser user) {
        //定义数据结构组合数据
        ReserveShipProductDto newReserveShipProduct = new ReserveShipProductDto();
        ReserveSingleProductDto reserveSingleProductDto = new ReserveSingleProductDto();
        ReserveBackProductDto reserveBackProductDto = new ReserveBackProductDto();
        List<ReserveProductDetailDTO> singleProductList = Lists.newArrayListWithExpectedSize(10);
        List<ReserveProductDetailDTO> backProductList = Lists.newArrayListWithExpectedSize(10);

        //信德和API的产品
        ReserveShipProductDto reserveShipProductDto = queryLocalShipReserve(shipProductSearchReq, user);
        ReserveShipProductDto reserveShipProductDto1 = queryPearlRiverShipReserve(shipProductSearchReq, user);

        //单程
        //信德
        if(reserveShipProductDto.getSingleProductDto() != null){
            List<ReserveProductDetailDTO> singleProductLists = reserveShipProductDto.getSingleProductDto().getSingleProductList();
            singleProductList.addAll(singleProductLists);
            reserveSingleProductDto.setDate(reserveShipProductDto.getSingleProductDto().getDate());
            reserveSingleProductDto.setDateStr(reserveShipProductDto.getSingleProductDto().getDateStr());
            reserveSingleProductDto.setArrCityName(reserveShipProductDto.getSingleProductDto().getArrCityName());
            reserveSingleProductDto.setDepCityName(reserveShipProductDto.getSingleProductDto().getDepCityName());
        }

        //API
        if(reserveShipProductDto1.getSingleProductDto() != null){
            List<ReserveProductDetailDTO> apiSingleProductList1 = reserveShipProductDto1.getSingleProductDto().getSingleProductList();
            singleProductList.addAll(apiSingleProductList1);
            reserveSingleProductDto.setDate(reserveShipProductDto1.getSingleProductDto().getDate());
            reserveSingleProductDto.setDateStr(reserveShipProductDto1.getSingleProductDto().getDateStr());
            reserveSingleProductDto.setArrCityName(reserveShipProductDto1.getSingleProductDto().getArrCityName());
            reserveSingleProductDto.setDepCityName(reserveShipProductDto1.getSingleProductDto().getDepCityName());
        }
        reserveSingleProductDto.setSingleProductList(singleProductList);

        //往返
        //信德
        if(reserveShipProductDto.getBackProductDto() != null){
            List<ReserveProductDetailDTO> backProductList1 = reserveShipProductDto.getBackProductDto().getBackProductList();
            backProductList.addAll(backProductList1);
            reserveBackProductDto.setDate(reserveShipProductDto.getBackProductDto().getDate());
            reserveBackProductDto.setDateStr(reserveShipProductDto.getBackProductDto().getDateStr());
            reserveBackProductDto.setArrCityName(reserveShipProductDto.getBackProductDto().getArrCityName());
            reserveBackProductDto.setDepCityName(reserveShipProductDto.getBackProductDto().getDepCityName());
        }

        //API
        if(reserveShipProductDto1.getBackProductDto() != null && CollectionUtil.isNotEmpty(reserveShipProductDto1.getBackProductDto().getBackProductList())){
            List<ReserveProductDetailDTO> backProductList2 = reserveShipProductDto1.getBackProductDto().getBackProductList();
            backProductList.addAll(backProductList2);
            reserveBackProductDto.setDate(reserveShipProductDto1.getBackProductDto().getDate());
            reserveBackProductDto.setDateStr(reserveShipProductDto1.getBackProductDto().getDateStr());
            reserveBackProductDto.setArrCityName(reserveShipProductDto1.getBackProductDto().getArrCityName());
            reserveBackProductDto.setDepCityName(reserveShipProductDto1.getBackProductDto().getDepCityName());
        }
        reserveBackProductDto.setBackProductList(backProductList);

        newReserveShipProduct.setSingleProductDto(reserveSingleProductDto);
        newReserveShipProduct.setBackProductDto(reserveBackProductDto);
        return newReserveShipProduct;
    }

    @Override
    public Result<PageResponse<AgentDto>> queryAgentList(AgentReq req) {
        IPage<ShipProduct> iPage = new Page<>(req.getPageNo(), req.getPageSize());
        IPage<AgentDto> agentList = shipProductMapper.queryAgentList(req,iPage);

        //校验
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isEmpty(agentList) || com.github.xiaoymin.knife4j.core.util.CollectionUtils.isEmpty(agentList.getRecords())) {
            return Result.success(new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize()));
        }
        List<AgentDto> useAgents = agentList.getRecords().stream().filter(dto -> dto.getVisableType() != 1).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(useAgents)){
            return Result.success(new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize()));
        }

        //是否全部代理商
        AgentDto agentDto = agentList.getRecords().stream().filter(entity->entity.getVisableType() == 2).findFirst().orElse(null);
        if(agentDto != null){
            SysAgentQueryListReq usableListReq = new SysAgentQueryListReq();
            if(org.apache.commons.lang.StringUtils.isNotEmpty(req.getAgentName())){
                usableListReq.setGroupName(req.getAgentName());
            }
            usableListReq.setPageNo(req.getPageNo());
            usableListReq.setPageSize(req.getPageSize());
            usableListReq.setStatus(1);
            usableListReq.setCheckStatus(4);

            BigDecimal exchangeRate = mainDataCurrencyService.getMarketRateById(agentDto.getCurrencyId());

            PageResponse<SysAgentQueryListDTO> listResult = sysAgentService.queryAgentList(usableListReq, null);
            if(listResult != null){
                List<AgentDto> agentDtos = listResult.getRecords().stream().map(entity -> {
                    AgentDto dto = new AgentDto();
                    dto.setAgentId(entity.getId());
                    dto.setAgentName(entity.getGroupCnName());
                    dto.setAgentFee(agentDto.getAgentFee());
                    dto.setTaxFee(agentDto.getTaxFee());
                    dto.setServiceChargePrice(agentDto.getServiceChargePrice().setScale(2,BigDecimal.ROUND_HALF_UP));
                    //加辐后的价格：成本价+代理加辐费
                    dto.setPrice(Objects.isNull(agentDto.getPrice().multiply(exchangeRate)) ? BigDecimal.ZERO : agentDto.getPrice()
                            .add(Objects.isNull(agentDto.getAgentFee()) ? BigDecimal.ZERO : agentDto.getAgentFee()).setScale(2,BigDecimal.ROUND_HALF_UP));
                    return dto;
                }).collect(Collectors.toList());
                return Result.success(new PageResponse<AgentDto>(agentDtos, iPage.getCurrent() == 1,
                        iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize()));
            }else {
                return Result.success(new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize()));
            }
        }
        //按照所选代理商返回
        agentList.getRecords().forEach(agent->{
            BigDecimal rate = mainDataCurrencyService.getMarketRateById(agent.getCurrencyId());
            agent.setPrice(Objects.isNull(agent.getPrice())?BigDecimal.ZERO:agent.getPrice().multiply(rate)
                    .add(Objects.isNull(agent.getAgentFee())?BigDecimal.ZERO :agent.getAgentFee()).setScale(2,BigDecimal.ROUND_HALF_UP));
        });
        return Result.success(new PageResponse<>(agentList.getRecords(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize()));
    }

    @Override
    public Result<Map<Integer,List<ShipBaseInfoDTO>>> queryShipPriceByDate(ShipPriceReq shipPriceReq) {
        List<ShipBaseInfoDTO> list = baseMapper.queryShipPriceByDate(shipPriceReq);
        if(CollectionUtils.isNotEmpty(list)){
            Map<Integer, List<ShipBaseInfoDTO>> listMap = list.stream().collect(Collectors.groupingBy(ShipBaseInfoDTO::getTouristTypeId));
            return Result.success(listMap);
        }
        return null;
    }

    @Override
    public List<ShipReservationGetOrderDTO> getOrderInfo(ShipReservationOrderReq shipReservationOrderReq) {
        List<ShipReservationGetOrderDTO> orderInfos = Lists.newArrayListWithExpectedSize(5);
        for(ConditionDTO conditionDTO : shipReservationOrderReq.getConditionReqList()){
            ShipProduct shipProduct = shipProductMapper.selectById(Long.valueOf(conditionDTO.getId()));
            QueryWrapper<ShipProductReservationSettings> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ShipProductReservationSettings::getShipProductId,Long.valueOf(conditionDTO.getId()));
            ShipProductReservationSettings shipProductReservationSettings = shipProductReservationSettingsMapper.selectOne(queryWrapper);
            if(shipProduct == null){
                throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
            }

            ShipPriceReq shipPriceReq = new ShipPriceReq();
            shipPriceReq.setQueryDate(conditionDTO.getQueryDate());
            shipPriceReq.setProductId(Long.valueOf(conditionDTO.getId()));
            List<ShipBaseInfoDTO> list = baseMapper.queryShipPriceByDate(shipPriceReq);

            if(CollectionUtils.isEmpty(list)){
                return orderInfos;
            }

            BigDecimal childPrice = BigDecimal.ZERO;
            BigDecimal adultPrice = BigDecimal.ZERO;
            BigDecimal oldPrice = BigDecimal.ZERO;

            BigDecimal beforeChildPrice = BigDecimal.ZERO;
            BigDecimal beforeAdultPrice = BigDecimal.ZERO;
            BigDecimal beforeOldPrice = BigDecimal.ZERO;

            //税费
            BigDecimal serviceFee = shipProductReservationSettings == null || shipProductReservationSettings.getServiceChargePrice() == null? BigDecimal.ZERO : new BigDecimal(shipProductReservationSettings.getServiceChargePrice());
            for(ShipBaseInfoDTO dto : list){
                switch (dto.getTouristTypeName()){
                    case "小童":
                        //成本加+ 加辐费 + 税费 + 预订服务费
                        BigDecimal exchangeRate1 = dto.getExchangeRate();
                        childPrice = dto.getCostPrice().multiply(exchangeRate1).add(dto.getAddFee()).add(dto.getTaxFee()).add(serviceFee).setScale(2,BigDecimal.ROUND_HALF_UP);;
                        beforeChildPrice = dto.getCostPrice().multiply(exchangeRate1).add(dto.getAddFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
                        break;
                    case "成人":
                        BigDecimal exchangeRate2 = dto.getExchangeRate();
                        adultPrice = dto.getCostPrice().multiply(exchangeRate2).add(dto.getAddFee()).add(dto.getTaxFee()).add(serviceFee).setScale(2,BigDecimal.ROUND_HALF_UP);;
                        beforeAdultPrice = dto.getCostPrice().multiply(exchangeRate2).add(dto.getAddFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
                        break;
                    case "長者":
                        BigDecimal exchangeRate3 = dto.getExchangeRate();
                        oldPrice = dto.getCostPrice().multiply(exchangeRate3).add(dto.getAddFee()).add(dto.getTaxFee()).add(serviceFee).setScale(2,BigDecimal.ROUND_HALF_UP);;
                        beforeOldPrice = dto.getCostPrice().multiply(exchangeRate3).add(dto.getAddFee()).setScale(2,BigDecimal.ROUND_HALF_UP);
                        break;
                    default:
                        break;
                }
            }

            ShipBaseInfoDTO dto = list.stream().findFirst().orElse(null);
            orderInfos.add(ShipReservationGetOrderDTO.builder().id(dto.getId()).code(dto.getCode()).cancelPolicy(shipProductReservationSettings.getCancelStrategy())
                    .bookingInformation(Objects.isNull(shipProductReservationSettings)?"":shipProductReservationSettings.getBookingInformation())
                    .kidTicketingInformation(Objects.isNull(shipProductReservationSettings)?"":shipProductReservationSettings.getKidTicketingInformation())
                    .passengerInformation(Objects.isNull(shipProductReservationSettings)?"":shipProductReservationSettings.getPassengerInformation())
                    .otherFeePrice(Objects.isNull(shipProductReservationSettings)?BigDecimal.ZERO:shipProductReservationSettings.getOtherFeePrice())
                    .isNeedCertificates(Objects.isNull(shipProductReservationSettings)?null:shipProductReservationSettings.getIsNeedCertificates())
                    .isNeedRoute(Objects.isNull(shipProductReservationSettings)?null:shipProductReservationSettings.getIsNeedRoute())
                    .serviceChargePrice(Objects.isNull(shipProductReservationSettings)?null:shipProductReservationSettings.getServiceChargePrice())
                    .childPrice(childPrice)
                    .adultPrice(adultPrice)
                    .oldPrice(oldPrice)
                    .beforeChildPrice(beforeChildPrice)
                    .beforeAdultPrice(beforeAdultPrice)
                    .beforeOldPrice(beforeOldPrice)
                    .depCityId(dto.getDepCityId()).depPlaceId(dto.getDepPlaceId()).cabinClass(dto.getCabinClass())
                    .arrCityId(dto.getArrCityId()).arrPlaceId(dto.getArrPlaceId())
                    .depCityName(Objects.isNull(dto)?"":dto.getDepCityName()).arrCityName(Objects.isNull(dto)?"":dto.getArrCityName())
                    .depPlaceName(Objects.isNull(dto)?"":dto.getDepPlaceName()).arrPlaceName(Objects.isNull(dto)?"":dto.getArrPlaceName())
                    .voyage(Objects.isNull(dto)?"":dto.getVoyage()).depTime(Objects.isNull(dto)?"":dto.getDepTime())
                    .cabinClassName(Objects.isNull(dto)?"":dto.getCabinClassName())
                    .build());
        }

        return orderInfos;
    }

    @Override
    public ShipProductInfoDTO queryShipProductDetail(Long id) {
        ShipProduct shipProduct = shipProductMapper.selectById(id);
        if(shipProduct == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
        }

        return EntityUtil.copy(shipProduct,ShipProductInfoDTO.class);
    }

    @Override
    public ShipProductReserveInfoDTO queryShipProductReserveDetail(Long id) {
        QueryWrapper<ShipProductReservationSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipProductReservationSettings::getShipProductId,id);
        ShipProductReservationSettings shipProductReservationSettings = shipProductReservationSettingsMapper.selectOne(queryWrapper);
        if(shipProductReservationSettings == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
        }
        return EntityUtil.copy(shipProductReservationSettings,ShipProductReserveInfoDTO.class);
    }

    @Override
    public void operateRepNumber(Integer number, Long productId, LocalDateTime depTime, boolean reduce) {
        //查询出发日期 对应的成本信息
        Long costId = baseMapper.selectActuallyCostForRoute(productId,DateUtil.toLocalDate(depTime));
        if(costId != null && costId != 0L){
            ShipProductCost shipProductCost = shipProductCostMapper.selectById(costId);
            if(reduce){
                //减库存
                shipProductCost.setDailyStock(shipProductCost.getDailyStock() - number);
            }else {
                //还库存
                shipProductCost.setDailyStock(shipProductCost.getDailyStock() + number);
            }
            shipProductCostMapper.updateById(shipProductCost);
        }
    }

    @Override
    public ShipPriceRemainderDTO findShipSalePriceInfoHandle(int strategyType, Long productId, LocalDate departureDate, Long relId) {
        ShipPriceRemainderDTO priceRemainder = new ShipPriceRemainderDTO();
        //1.构建成本價+加幅費
        switch (strategyType){
            case 1:
                List<ShipAddPriceDTO> allAttrsPriceList =baseMapper.queryOffLineSalePrice(productId,departureDate);
                //校验产品用户是否设置加辐费
                checkUserCandidate(relId, allAttrsPriceList);
                //构建产品价格信息
                buildOfflinePriceInfo(priceRemainder, allAttrsPriceList,departureDate);
                break;
            case 2:
                List<ShipAddPriceDTO> agentPriceList =baseMapper.queryAgentSalePrice(productId,departureDate);
                //校验产品用户是否设置加辐费
                checkUserCandidate(relId, agentPriceList);
                //构建产品价格信息
                buildOfflinePriceInfo(priceRemainder, agentPriceList, departureDate);
                break;
            case 3:
                //获取官方平台产品渠道的加辐
                List<ShipAddPriceDTO> officeDtoList = baseMapper.querySaleOfficePrice(productId,departureDate,relId);
                if(CollectionUtils.isEmpty(officeDtoList)){
                    throw new BusinessException(SystemError.LOCAL_FUN_18027);
                }
                //构建产品价格信息
                buildOfflinePriceInfo(priceRemainder, officeDtoList, departureDate);
                break;
            case 4:
                //获取官方平台产品渠道的加辐
                List<ShipAddPriceDTO> thirdDtoList = baseMapper.querySaleThirdPrice(productId,departureDate,relId);
                if(CollectionUtils.isEmpty(thirdDtoList)){
                    throw new BusinessException(SystemError.LOCAL_FUN_18027);
                }
                //构建产品价格信息
                buildOfflinePriceInfo(priceRemainder, thirdDtoList, departureDate);
                break;
            default:
                break;
        }

        //2.设置預定服務費
        ShipProductReservationSettings settings = shipProductReservationSettingsMapper.selectOne(Wrappers.<ShipProductReservationSettings>lambdaQuery()
                .eq(ShipProductReservationSettings::getShipProductId,productId));
        if(settings == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
        }
        //1 金額
        if(settings.getServiceChargeType() == 1){
            priceRemainder.setReserveCharge(new BigDecimal(settings.getServiceChargePrice()));
        }
        //百分比
        else {
            BigDecimal reserveCharge = priceRemainder.getCostPrice().multiply(new BigDecimal(settings.getServiceChargePrice()*0.01));
            priceRemainder.setReserveCharge(reserveCharge);
        }
        return priceRemainder;
    }


    /**
     * 校验该产品用户是否设置产品加辐费
     * @param relId
     * @param allAttrsPriceList
     */
    protected void checkUserCandidate(Long relId, List<ShipAddPriceDTO> allAttrsPriceList) {
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(allAttrsPriceList)){
            ShipAddPriceDTO localFunAddPriceDTO = allAttrsPriceList.stream().findFirst().orElse(null);
            if(localFunAddPriceDTO != null){
                if(localFunAddPriceDTO.getVisableType() == 3){
                    if(relId == null){
                        throw new BusinessException(SystemError.LOCAL_FUN_18020);
                    }
                    List<String> relationIds = getUserIdsByUserId(relId);
                    allAttrsPriceList = allAttrsPriceList.stream().filter(entity->relationIds.contains(entity.getRelationId())).collect(Collectors.toList());
                }
            }
        }
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isEmpty(allAttrsPriceList)){
            throw new BusinessException(SystemError.LOCAL_FUN_18026);
        }
    }


    /**
     * 構建線下自營渠道 價格
     * @param priceRemainder
     * @param allAttrsPriceList
     * @param departureDate
     */
    protected void buildOfflinePriceInfo(ShipPriceRemainderDTO priceRemainder, List<ShipAddPriceDTO> allAttrsPriceList, LocalDate departureDate) {
        ShipAddPriceDTO minPriceDto = allAttrsPriceList.stream().min(Comparator.comparing(ShipAddPriceDTO::getCostAndFee)).get();
        if(minPriceDto != null){
            priceRemainder.setCostPrice(minPriceDto.getCostPrice());
            priceRemainder.setExchangeRate(minPriceDto.getExchangeRate());
            priceRemainder.setPrice(Objects.isNull(minPriceDto.getCostAndFee()) ? null :minPriceDto.getCostAndFee().setScale(2,BigDecimal.ROUND_HALF_UP));
            priceRemainder.setSolidNumber(querySolidNumber(minPriceDto,departureDate));
            return;
        }

    }

    /**
     * 余票计算
     * @param minPriceDto
     * @param departureDate
     * @return
     */
    private Integer querySolidNumber(ShipAddPriceDTO minPriceDto, LocalDate departureDate) {
        //总库存
        Integer solidStock = minPriceDto.getSolidStock();
        //今日可售额
        Integer limitNum = minPriceDto.getLimitNum();
        //限购今日售额
        if(minPriceDto.getIsLimit() != null && minPriceDto.getIsLimit() == 1){
            //余票=库存-产品已售额
            if(limitNum > solidStock){
                Integer soldCount = 0;
                //查询产品已售额
                List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                        .eq(ShipProductSaleRecord::getProductId, minPriceDto.getProductId()));
                if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                    soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
                }
                return solidStock - soldCount;
            }
            //余票=今日可售额-今日已售额
            else {
                if(limitNum == null || limitNum == 0){
                    throw new BusinessException(SystemError.SHIP_PRODUCT_11051);
                }
                Integer soldCount = 0;
                //查询今日产品已售额
                List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                        .eq(ShipProductSaleRecord::getProductId, minPriceDto.getProductId())
                .eq(ShipProductSaleRecord::getSalesDate,departureDate));

                if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                    soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
                }
                return limitNum - soldCount;
            }
        }else {
            Integer soldCount = 0;
            //查询产品已售额
            List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                    .eq(ShipProductSaleRecord::getProductId, minPriceDto.getProductId()));
            if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
            }
            return solidStock - soldCount;
        }
    }


    /**
     * 价格
     * @param entity
     * @param shipInitializationSettings
     * @return
     */
    private String getPrice(ShipReserveListDTO entity, ShipInitializationSettings shipInitializationSettings) {
        if(entity.getCompanyType() == 2){

//            BigDecimal hkd = mainDataCurrencyService.getExchangeRate(entity.getCurrencyName(),CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);
            entity.setCosPrice(entity.getCosPrice().multiply(Objects.isNull(entity.getExchangeRate())?BigDecimal.ONE:entity.getExchangeRate()));

            BigDecimal totalAmount = new BigDecimal("0");
            //判断是加百分比还是加价格
            if (shipInitializationSettings.getBookingPriceType() == ShipConstants.ADJUST_TYPE_PERCENT) {
                double percent = shipInitializationSettings.getBookingPrice();
                percent = percent * 0.01;
                //成本价*百分比+服务费+税费
                totalAmount = totalAmount.add(entity.getCosPrice().multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP));
            } else {
                totalAmount = totalAmount.add(new BigDecimal(shipInitializationSettings.getBookingPrice()));
            }
            //加辐费
            BigDecimal orderPrice = entity.getOrderPrice() != null ? entity.getOrderPrice() : BigDecimal.ZERO;

            return entity.getCosPrice().add(totalAmount).add(orderPrice).setScale(2,BigDecimal.ROUND_HALF_UP).toString();
        }else {
            //成本价格
            BigDecimal costPrice = entity.getCosPrice() == null ? BigDecimal.ZERO : entity.getCosPrice();
            //成本价转港币
            BigDecimal hkd = entity.getExchangeRate();

            //税费
            BigDecimal taxPrice = entity.getTaxPrice() == null ? BigDecimal.ZERO : entity.getTaxPrice();

            //加辐费
            BigDecimal orderPrice = entity.getOrderPrice() != null ? entity.getOrderPrice() : BigDecimal.ZERO;
            //成本价+加辐费+税费+预订服务费
            return costPrice.multiply(hkd).add(entity.getServicePrice()).add(taxPrice).add(orderPrice).setScale(2,BigDecimal.ROUND_HALF_UP).toString();
        }

    }

//    /**
//     * 信德产品详情
//     * @param reserveReq
//     * @param user
//     * @return
//     */
//    private List<ReserveProductDetailDTO> getReserveShipProductDetail(ReserveReq reserveReq, TokenUser user) {
//        List<String> userIds = getUserIdsByUserId(user.getId());
//        ShipProductIsRecommendedReq shipProductIsRecommendedReq = queryCondition(reserveReq);
//        List<ShipReserveListDTO> singleShipReserveList = shipProductMapper.selectShipReserveNewList(shipProductIsRecommendedReq, userIds);
//        if(CollectionUtils.isEmpty(singleShipReserveList)) {
//            return Lists.newArrayListWithExpectedSize(1);
//        }
//
//        //服务费
//        QueryWrapper<ShipInitializationSettings> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(ShipInitializationSettings::getIsDeleted, ShipConstants.NOT_DELETE);
//        ShipInitializationSettings shipInitializationSettings = shipInitializationSettingsMapper.selectOne(queryWrapper);
//
//        //按产品分组
//        Map<Long, List<ShipReserveListDTO>> shipReserveMap =
//                singleShipReserveList.stream().collect(Collectors.groupingBy(ShipReserveListDTO::getId));
//
//        List<ReserveProductDetailDTO> detailList = Lists.newArrayListWithExpectedSize(10);
//        shipReserveMap.forEach((productId,productList)->{
//            List<ShipReserveListDTO> childProductList = Lists.newArrayListWithExpectedSize(10);
//            //获取价格最小的一条数据
//            childProductList.add(productList.stream().min(Comparator.comparing(ShipReserveListDTO::getCosPrice)).get());
//
//            if(CollectionUtils.isNotEmpty(childProductList)){
//                ShipReserveListDTO entity = childProductList.stream().findFirst().orElse(null);
//                if(entity != null){
//                    detailList.add(ReserveProductDetailDTO.builder().arrPlaceName(entity.getArrPlaceName())
//                            .depPlaceName(entity.getDepPlaceName())
//                            .depTime(entity.getDepTime())
//                            .distanceTime("60")
//                            .productId(entity.getId())
//                            .routeId(entity.getRouteId())
//                            .routeName(entity.getRouteName())
//                            .voyage(entity.getVoyage())
//                            .price(entity.getPrice().toString())
//                            .childDtoList(wrapperChildList(entity, productList,shipInitializationSettings)).build());
//                }
//            }
//        });
//        return detailList;
//    }

    /**
     * 预订 票规格
     *
     * @param dto
     * @param productList
     * @return
     */
    private List<ReserveProductChildDto> wrapperChildList(ShipReserveListDTO dto, List<ShipReserveListDTO> productList) {
        List<ReserveProductChildDto> resultList = Lists.newArrayListWithExpectedSize(5);
        //按供应商分组
        Map<String, List<ShipReserveListDTO>> shipReserveMap =
                productList.stream().collect(Collectors.groupingBy(ShipReserveListDTO::getSupplierName));

        shipReserveMap.forEach((productId,list)->{
            //按仓位等级分组
            Map<String, List<ShipReserveListDTO>> shipReserveMap2 =
                    productList.stream().collect(Collectors.groupingBy(ShipReserveListDTO::getCabinClassStr));

            shipReserveMap2.forEach((cabinClassName,list2)->{
                ShipReserveListDTO entity = list2.stream().findFirst().orElse(null);
                //获取成人、小童、长者价格
                Map<String, List<ShipReserveListDTO>> priceMap = list.stream().filter(en-> StringUtil.isNotEmpty(en.getTouristName())).collect(Collectors.groupingBy(ShipReserveListDTO::getTouristName));

                PriceDTO priceDTO = obtainPrice(priceMap,entity);

                if(entity != null){
                    resultList.add(ReserveProductChildDto.builder()
                            .area(entity.getApplicableCrowdName())
                            .cabinClass(entity.getCompanyType() == 1? entity.getCabinClassStr() : entity.getSeatRanktName())
                            .depPlaceEnName(entity.getDepPlaceName()).arrPlaceEnName(entity.getArrPlaceName())
                            .productId(entity.getId())
                            .routeId(entity.getRouteId())
                            .depTime(entity.getDepTime())
                            .depCityName(entity.getDepCityName()).arrCityName(entity.getArrCityName())
                            .routeName(entity.getRouteName())
                            .touristId(entity.getTouristId())
                            .confirm(entity.getIsConfirm() == 1?"即時確認":"")
                            .surplusNumber(getSurplusNumber(entity))
                            .supplierName(entity.getSupplierName())
                            .supplierId(entity.getSupplierId())
                            .childAmount(priceDTO.getChildAmount())
                            .adultAmount(priceDTO.getAdultAmount())
                            .oldAdultAmount(priceDTO.getOldAdultAmount())
                            .build());
                }
            });

        });
        return resultList;
    }

    /**
     * 获取余票
     * @param entity
     * @return
     */
    private Integer getSurplusNumber(ShipReserveListDTO entity) {
        //总库存
        Integer solidStock = entity.getTotalNumber();
        //今日可售额
        Integer limitNum = entity.getLimitNum();
        //限购今日售额
        if(entity.getIsLimit() != null && entity.getIsLimit() == 1){
            //余票=库存-产品已售额
            if(limitNum > solidStock){
                Integer soldCount = 0;
                //查询产品已售额
                List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                        .eq(ShipProductSaleRecord::getProductId, entity.getId()));
                if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                    soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
                }
                return solidStock - soldCount;
            }
            //余票=今日可售额-今日已售额
            else {
                if(limitNum == null || limitNum == 0){
                    throw new BusinessException(SystemError.SHIP_PRODUCT_11051);
                }
                Integer soldCount = 0;
                //查询今日产品已售额
                List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                        .eq(ShipProductSaleRecord::getProductId, entity.getId())
                        .eq(ShipProductSaleRecord::getSalesDate,LocalDate.now()));

                if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                    soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
                }
                return limitNum - soldCount;
            }
        }else {
            Integer soldCount = 0;
            //查询产品已售额
            List<ShipProductSaleRecord> shipProductSaleRecords = shipProductSaleRecordMapper.selectList(Wrappers.<ShipProductSaleRecord>lambdaQuery()
                    .eq(ShipProductSaleRecord::getProductId, entity.getId()));
            if(CollectionUtil.isNotEmpty(shipProductSaleRecords)){
                soldCount = shipProductSaleRecords.stream().mapToInt(ShipProductSaleRecord::getSoldNumber).sum();
            }
            return solidStock - soldCount;
        }
    }


    /**
     * 设置小童、成人、长者价格
     * @param priceMap
     * @param entity
     * @return
     */
    private PriceDTO obtainPrice(Map<String, List<ShipReserveListDTO>> priceMap, ShipReserveListDTO entity) {
        PriceDTO priceDTO = new PriceDTO();
        if(!priceMap.isEmpty()){
            List<ShipReserveListDTO> shipReserveListDTOS1 = priceMap.get("小童");
            List<ShipReserveListDTO> shipReserveListDTOS2 = priceMap.get("成人");
            List<ShipReserveListDTO> shipReserveListDTOS3 = priceMap.get("長者");

            priceDTO.setChildAmount(setSpecialPrice(shipReserveListDTOS1,entity));
            priceDTO.setAdultAmount(setSpecialPrice(shipReserveListDTOS2,entity));
            priceDTO.setOldAdultAmount(setSpecialPrice(shipReserveListDTOS3,entity));
        }
        return priceDTO;
    }

    /**
     * 设置价格
     * @param shipReserveListDTOS3
     * @param entity
     */
    private String setSpecialPrice(List<ShipReserveListDTO> shipReserveListDTOS3, ShipReserveListDTO entity) {
        String childAmount = "0 HKD";
        if(CollectionUtil.isNotEmpty(shipReserveListDTOS3)){
            ShipReserveListDTO shipReserveListDTO3 = shipReserveListDTOS3.stream().findFirst().orElse(null);
            if(shipReserveListDTO3 != null){
                childAmount = getPrice(shipReserveListDTO3, null) + " HKD";
            }
        }
        return childAmount;
    }


    /**
     * 查询条件
     * @param reserveReq
     * @return
     */
    private ShipProductIsRecommendedReq queryCondition(ReserveReq reserveReq) {
        ShipProductIsRecommendedReq shipProductIsRecommendedReq = new ShipProductIsRecommendedReq();
        shipProductIsRecommendedReq.setStartDate(LocalDate.now());
        //出发地 目的地 出发日期
        shipProductIsRecommendedReq.setDepCityId(reserveReq.getDepCityId());
        shipProductIsRecommendedReq.setArrCityId(reserveReq.getArrCityId());
//        shipProductIsRecommendedReq.setDepTimeStart(reserveReq.getDepTimeStart());

        //出发时间段
        if(reserveReq.getDepTimeStart() != null){
            shipProductIsRecommendedReq.setDepDateStart(reserveReq.getDepTimeStart());
        }
        if(reserveReq.getArrTimeStart() != null){
            shipProductIsRecommendedReq.setDepDateEnd(reserveReq.getArrTimeStart());
        }
        //船舱等级
        if(!StringUtils.isEmpty(reserveReq.getCabinClass())){
            shipProductIsRecommendedReq.setCabinClass(reserveReq.getCabinClass().toString());
        }
        return shipProductIsRecommendedReq;
    }


    /**
     * 预订中心 条件查询珠江产品列表
     * @param shipProductSearchReq
     * @param user
     * @return
     */
    private ReserveShipProductDto queryPearlRiverShipReserve(ShipProductSearchReq shipProductSearchReq, TokenUser user) {
        ReserveShipProductDto reserveShipProductDto = new ReserveShipProductDto();

        StopWatch stopWatch = new StopWatch("companyType = 2-------->");
        //单程
        if(shipProductSearchReq.getTicketType() == 1L){
            stopWatch.start("单程");
            ReserveCityDto cityDto = getReserveCity(1,shipProductSearchReq.getDepPlaceName(),shipProductSearchReq.getArrPlaceName(),shipProductSearchReq.getDepPlaceId(),shipProductSearchReq.getArrPlaceId());
            reserveShipProductDto.setSingleProductDto(ReserveSingleProductDto.builder()
                    .date(shipProductSearchReq.getDepTimeStart())
                    .dateStr(conventDateStr(shipProductSearchReq.getDepTimeStart()))
                    .depCityName(Objects.isNull(cityDto)?"":cityDto.getDepCityName())
                    .arrCityName(Objects.isNull(cityDto)?"":cityDto.getArrCityName())
                    .singleProductList(getShipReserveTicket(shipProductSearchReq)).build());

            stopWatch.stop();
        }
        //返程
        else {
            stopWatch.start("返程");
            //去程 产品列表
            shipProductSearchReq.setTicketType(1L);
            List<ReserveProductDetailDTO>  singleTicket = getShipReserveTicket(shipProductSearchReq);

            //返程 产品列表
            String arrPlaceCode = shipProductSearchReq.getArrPlaceCode();
            String depPlaceCode = shipProductSearchReq.getDepPlaceCode();
            shipProductSearchReq.setDepPlaceCode(arrPlaceCode);
            shipProductSearchReq.setArrPlaceCode(depPlaceCode);
            shipProductSearchReq.setTicketType(2L);

            List<ReserveProductDetailDTO>  backTicket = getShipReserveTicket(shipProductSearchReq);
            if(CollectionUtils.isNotEmpty(backTicket)){
                singleTicket.addAll(backTicket);
            }

            ReserveCityDto cityDto = getReserveCity(1,shipProductSearchReq.getArrPlaceName(),shipProductSearchReq.getDepPlaceName(),shipProductSearchReq.getDepPlaceId(),shipProductSearchReq.getArrPlaceId());
            reserveShipProductDto.setBackProductDto(ReserveBackProductDto.builder()
                    .date(shipProductSearchReq.getDepTimeStart())
                    .dateStr(conventDateStr(shipProductSearchReq.getArrTimeStart()))
                    .depCityName(Objects.isNull(cityDto)?"":shipProductSearchReq.getDepCityName())
                    .arrCityName(Objects.isNull(cityDto)?"":shipProductSearchReq.getArrCityName())
                    .backProductList(singleTicket).build());

            stopWatch.stop();
        }
        log.info("companyType = 2,Query list cost :{}",stopWatch.prettyPrint() +" ms");
        return reserveShipProductDto;
    }

    /**
     * 获取产品
     * @param shipProductSearchReq
     * @return
     */
    private List<ReserveProductDetailDTO> getShipReserveTicket(ShipProductSearchReq shipProductSearchReq) {
        List<ShipReserveListDTO> shipList = Lists.newArrayListWithExpectedSize(10);
        List<ReserveProductDetailDTO> shipListNew = Lists.newArrayListWithExpectedSize(10);
        List<ShipReserveListDTO> list = shipProductMapper.selectNewApiList(shipProductSearchReq);
        if(CollectionUtils.isEmpty(list)){
            return shipListNew;
        }

        Map<Long, List<ShipReserveListDTO>> shipReserveMap =
                list.stream().collect(Collectors.groupingBy(ShipReserveListDTO::getId));
        //获取价格最小的一条数据
        shipReserveMap.forEach((productId,productList)-> shipList.add(list.stream().min(Comparator.comparing(ShipReserveListDTO::getCosPrice)).get()));

        QueryWrapper<ShipInitializationSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipInitializationSettings::getIsDeleted, ShipConstants.NOT_DELETE);
        ShipInitializationSettings shipInitializationSettings = shipInitializationSettingsMapper.selectOne(queryWrapper);

        shipReserveMap.forEach((productId,productList)->{
            List<ShipReserveListDTO> childProductList = Lists.newArrayListWithExpectedSize(10);
            //获取价格最小的一条数据
            childProductList.add(productList.stream().min(Comparator.comparing(ShipReserveListDTO::getCosPrice)).get());

            if(CollectionUtils.isNotEmpty(childProductList)){
                ShipReserveListDTO entity = childProductList.stream().findFirst().orElse(null);
                if(entity != null){
                    shipListNew.add(ReserveProductDetailDTO.builder().arrPlaceName(entity.getArrPlaceName())
                            .depPlaceName(entity.getDepPlaceName())
                            .depTime(entity.getDepTime())
                            .productId(entity.getId())
                            .routeId(entity.getRouteId())
                            .routeName(entity.getRouteName())
                            .voyage(entity.getVoyage())
                            .price(getPrice(entity,shipInitializationSettings))
                            .childDtoList(wrapperChildList(entity,productList)).build());
                }
            }
        });
        return shipListNew;
    }


    /**
     * 预订中心  条件查询 信德产品列表
     * @param shipProductSearchReq
     * @param user
     * @return
     */
    private ReserveShipProductDto queryLocalShipReserve(ShipProductSearchReq shipProductSearchReq, TokenUser user) {
        ReserveShipProductDto reserveShipProductDto = new ReserveShipProductDto();

        StopWatch stopWatch = new StopWatch("companyType = 1-------->");
        //单程
        if(shipProductSearchReq.getTicketType() == 1L){
            stopWatch.start("单程");
            ReserveCityDto cityDto = getReserveCity(1,shipProductSearchReq.getDepPlaceName(),shipProductSearchReq.getArrPlaceName(),shipProductSearchReq.getDepPlaceId(),shipProductSearchReq.getArrPlaceId());
            reserveShipProductDto.setSingleProductDto(ReserveSingleProductDto.builder()
                    .dateStr(conventDateStr(shipProductSearchReq.getDepTimeStart()))
                    .date(shipProductSearchReq.getDepTimeStart())
                    .depCityName(Objects.isNull(cityDto)?"":cityDto.getDepCityName())
                    .arrCityName(Objects.isNull(cityDto)?"":cityDto.getArrCityName())
                    .singleProductList(handleShipReserveList(shipProductSearchReq,user)).build());

            stopWatch.stop();
        }
        //往返
        else {
            stopWatch.start("往返");
            //出发日期的产品
            shipProductSearchReq.setTicketType(1L);
            ReserveCityDto cityDto = getReserveCity(1,shipProductSearchReq.getDepPlaceName(),shipProductSearchReq.getArrPlaceName(),shipProductSearchReq.getDepPlaceId(),shipProductSearchReq.getArrPlaceId());
            List<ReserveProductDetailDTO> singleShipReserveList = handleShipReserveList(shipProductSearchReq,user);
            reserveShipProductDto.setSingleProductDto(ReserveSingleProductDto.builder()
                    .dateStr(conventDateStr(shipProductSearchReq.getDepTimeStart()))
                    .depCityName(Objects.isNull(cityDto)?"":cityDto.getDepCityName())
                    .arrCityName(Objects.isNull(cityDto)?"":cityDto.getArrCityName())
                    .date(shipProductSearchReq.getDepTimeStart()).singleProductList(singleShipReserveList).build());

            //出发地、目的地
            Long depCityId = shipProductSearchReq.getDepCityId();
            Long arrCityId = shipProductSearchReq.getArrCityId();
            //出发码头、达到码头
            Long depPlaceId = shipProductSearchReq.getDepPlaceId();
            Long arrPlaceId = shipProductSearchReq.getArrPlaceId();

            //返程日期的产品
            shipProductSearchReq.setTicketType(2L);
            //出发地、目的地，城市反向
            shipProductSearchReq.setArrCityId(depCityId);
            shipProductSearchReq.setDepCityId(arrCityId);
            //出发码头、达到码头 ,码头反向
            shipProductSearchReq.setDepPlaceId(arrPlaceId);
            shipProductSearchReq.setArrPlaceId(depPlaceId);
            shipProductSearchReq.setDepTimeStart(shipProductSearchReq.getArrTimeStart());

            ReserveCityDto cityDto2 = getReserveCity(1,shipProductSearchReq.getArrPlaceName(),shipProductSearchReq.getDepPlaceName(),shipProductSearchReq.getDepPlaceId(),shipProductSearchReq.getArrPlaceId());
            List<ReserveProductDetailDTO> backShipReserveList = handleShipReserveList(shipProductSearchReq,user);
            reserveShipProductDto.setBackProductDto(ReserveBackProductDto.builder()
                    .date(shipProductSearchReq.getArrTimeStart())
                    .depCityName(Objects.isNull(cityDto2)?"":cityDto2.getDepCityName())
                    .arrCityName(Objects.isNull(cityDto2)?"":cityDto2.getArrCityName())
                    .dateStr(conventDateStr(shipProductSearchReq.getArrTimeStart())).backProductList(backShipReserveList).build());

            stopWatch.stop();
        }
        log.info("companyType = 1,Query list cost :{}",stopWatch.prettyPrint() +" ms");
        return reserveShipProductDto;
    }

    private ReserveCityDto getReserveCity(int compantType, String depPlaceName, String arrPlaceName,Long depPlaceId,Long arrPlaceId) {
        if(compantType == 1){
            ReserveCityDto cityDto = shipProductMapper.queryReserveCity(depPlaceName, arrPlaceName);
            if(cityDto == null){
                cityDto = shipProductMapper.queryReserveIdCity(depPlaceId, arrPlaceId);
                return cityDto;
            }
            return cityDto;
        }
        return null;
    }

    /**
     * 时间 - 格式化 月-日 周
     * @param depTimeStart
     * @return
     */
    private String conventDateStr(LocalDateTime depTimeStart) {
        if(depTimeStart == null){
            return "";
        }
        //周
        Integer week = depTimeStart.getDayOfWeek().getValue();

        String weekStr = "";
        switch (week){
            case 1:
                weekStr = "周一";
                break;
            case 2:
                weekStr = "周二";
                break;
            case 3:
                weekStr = "周三";
                break;
            case 4:
                weekStr = "周四";
                break;
            case 5:
                weekStr = "周五";
                break;
            case 6:
                weekStr = "周六";
                break;
            case 7:
                weekStr = "周日";
                break;
            default:
                weekStr = "";
        }
        //月
        int monthValue = depTimeStart.getMonthValue();

        //日
        int dayOfMonth = depTimeStart.getDayOfMonth();
        return (monthValue < 10 ?"0" : "") + monthValue + (dayOfMonth < 10 ?"月0" : "月") + dayOfMonth +"日 "+ weekStr;
    }


    /**
     * 查询满足条件的产品列表
     * 查询条件：1.出发地、目的地；2.出发码头、到达码头；3.船舱等级，4.出发日期
     * @param shipProductSearchReq
     * @param user
     * @return
     */
    private List<ReserveProductDetailDTO> handleShipReserveList(ShipProductSearchReq shipProductSearchReq, TokenUser user){
        //查询出所有的产品
        List<String> userIds = getUserIdsByUserId(user.getId());
        //设置startDate,用于查询有效时效的产品
        setUseTimeBetweenValidateTime(shipProductSearchReq);
        List<ShipReserveListDTO> singleShipReserveList = shipProductMapper.selectShipReserveNewList(shipProductSearchReq, null);
        singleShipReserveList = singleShipReserveList.stream().filter(entity->{
            if(entity.getVisableType() == 3){
                return userIds.contains(String.valueOf(entity.getRelationId()));
            }
            return true;
        }).collect(Collectors.toList());


        //按产品分组
        Map<Long, List<ShipReserveListDTO>> shipReserveMap =
                singleShipReserveList.stream().collect(Collectors.groupingBy(ShipReserveListDTO::getId));

        List<ReserveProductDetailDTO> detailList = Lists.newArrayListWithExpectedSize(10);
        shipReserveMap.forEach((productId,productList)->{
            List<ShipReserveListDTO> childProductList = Lists.newArrayListWithExpectedSize(10);
            //获取价格最小的一条数据
            childProductList.add(productList.stream().min(Comparator.comparing(ShipReserveListDTO::getCosPrice)).get());

            if(CollectionUtils.isNotEmpty(childProductList)){
                ShipReserveListDTO entity = childProductList.stream().findFirst().orElse(null);
                if(entity != null){
                    detailList.add(ReserveProductDetailDTO.builder().arrPlaceName(entity.getArrPlaceName())
                            .depPlaceName(entity.getDepPlaceName())
                            .depTime(entity.getDepTime())
                            .productId(entity.getId())
                            .routeId(entity.getRouteId())
                            .routeName(entity.getRouteName())
                            .voyage(entity.getVoyage())
                            .price(getPrice(entity, null))
                            .childDtoList(wrapperChildList(entity,productList)).build());
                }
            }
        });

        if(!StringUtils.isEmpty(shipProductSearchReq.getStartTime())){
            return detailList.stream().filter(entity ->
                    filterValidTime(entity,shipProductSearchReq.getStartTime(),shipProductSearchReq.getEndTime())).collect(Collectors.toList());
        }
        return detailList;
    }

    /**
     * 过滤时间段
     * @param entity
     * @param startTime
     * @param endTime
     * @return
     */
    private boolean filterValidTime(ReserveProductDetailDTO entity, String startTime, String endTime) {
        String depTime = entity.getDepTime();

        String[] split = depTime.split(":");
        Integer hour = Integer.valueOf(split[0]);
        Integer min = Integer.valueOf(split[1]);

        String[] start = startTime.split(":");
        Integer hourStart = Integer.valueOf(start[0]);
        Integer minStart = Integer.valueOf(start[1]);

        String[] end = endTime.split(":");
        Integer hourEnd = Integer.valueOf(end[0]);
        Integer minEnd = Integer.valueOf(end[1]);

        if(hour > hourStart && hour < hourEnd){
            return true;
        }
        if(hour == hourStart && (min >= minStart && min <= minEnd)){
            return true;
        }
        if(hour == hourEnd && (min >= minStart && min <= minEnd)){
            return true;
        }
        return false;
    }

    /**
     * 设置出发日期或返程日期 查询有效期范围内的产品
     * @param shipProductIsRecommendedReq
     */
    private void setUseTimeBetweenValidateTime(ShipProductSearchReq shipProductIsRecommendedReq) {
        if(shipProductIsRecommendedReq.getCompanyType() == null){
            return;
        }
        if(shipProductIsRecommendedReq.getTicketType() == 1){
            //出发日期
            if(shipProductIsRecommendedReq.getDepTimeStart() == null){
                throw new BusinessException(SystemError.SHIP_PRODUCT_11044);
            }
            shipProductIsRecommendedReq.setStartDate(shipProductIsRecommendedReq.getDepTimeStart().toLocalDate());
        }else if(shipProductIsRecommendedReq.getTicketType() == 2){
            if(shipProductIsRecommendedReq.getDepTimeStart() == null || shipProductIsRecommendedReq.getArrTimeStart() == null){
                throw new BusinessException(SystemError.SHIP_PRODUCT_11045);
            }
            //返程日期
            shipProductIsRecommendedReq.setStartDate(shipProductIsRecommendedReq.getArrTimeStart().toLocalDate());
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result updateApiSetting(ShipProductUpdateApiSettingReq shipProductUpdateApiSettingReq) {
        Long id = shipProductUpdateApiSettingReq.getIds();
        ShipProduct shipProduct = shipProductMapper.selectOne(new QueryWrapper<ShipProduct>().lambda().eq(ShipProduct::getId, id));
        shipProduct.setPackStatus(shipProductUpdateApiSettingReq.getPackStatus());
        shipProduct.setChargeUserId(shipProductUpdateApiSettingReq.getChargeUserId());
        shipProduct.setChargeUserName(shipProductUpdateApiSettingReq.getChargeUser());

        shipProductMapper.updateById(shipProduct);

        ShipProductReservationSettings shipProductReservationSettings = shipProductReservationSettingsMapper.selectOne(
                new QueryWrapper<ShipProductReservationSettings>().lambda().eq(ShipProductReservationSettings::getShipProductId, id));

        shipProductReservationSettings.setServiceChargeType(shipProductUpdateApiSettingReq.getBookingPriceType());
        shipProductReservationSettings.setServiceChargePrice(shipProductUpdateApiSettingReq.getBookingPrice());

        shipProductReservationSettings.setRefundFeeType(shipProductUpdateApiSettingReq.getRefundFeePriceType());
        shipProductReservationSettings.setRefundFeePrice(shipProductUpdateApiSettingReq.getRefundFeePrice());
        shipProductReservationSettingsMapper.updateById(shipProductReservationSettings);
        return Result.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result updateSetting(ShipProductUpdateSettingReq shipProductUpdateSettingReq) {
        List<Long> ids = shipProductUpdateSettingReq.getIds();
        for (Long id : ids) {
            ShipProduct shipProduct = shipProductMapper.selectOne(new QueryWrapper<ShipProduct>().lambda().eq(ShipProduct::getId, id));
            if(shipProductUpdateSettingReq.getChargeUserId() != null){
                shipProduct.setChargeUserId(shipProductUpdateSettingReq.getChargeUserId());
            }
            if(!StringUtils.isEmpty(shipProductUpdateSettingReq.getChargeUser())){
                shipProduct.setChargeUserName(shipProductUpdateSettingReq.getChargeUser());
            }
            if(shipProductUpdateSettingReq.getSellStatus() != null){
                shipProduct.setSellStatus(shipProductUpdateSettingReq.getSellStatus());
            }
            if(shipProductUpdateSettingReq.getPackStatus() != null){
                shipProduct.setPackStatus(shipProductUpdateSettingReq.getPackStatus());
            }
            shipProductMapper.updateById(shipProduct);
        }
        return Result.success();
    }


    /**
     * 新增-编辑提交审批
     *
     * @param submitReq
     * @param user
     */
    @Override
    public Result submit(SubmitReq submitReq, TokenUser user) {
        for(Long productId : submitReq.getProductIds()){
            Result<ApprovalStartDTO> result = iSysApprovalService.start(SystemBusinessType.SHIP_TICKET.getCode(),
                    SysApprovalType.ADD_SHIP.getCode(),productId,user.getId(),null,null);

            if(result.isSuccess()){
                ShipProduct shipProduct = shipProductMapper.selectById(productId);
                if (Objects.isNull(shipProduct)) {
                    return Result.failed(SystemError.SHIP_PRODUCT_11006);
                }
                shipProduct.setApprovalStatus(ScenicApproveType.PROCESSED.getCode());
                baseMapper.updateById(shipProduct);
            }else {
                Result result1 = new Result();
                result1.setCode(result.getCode());
                result1.setMsg(result.getMsg());
                return result1;
            }
        }
        return Result.success();
    }

    /**
     * 查询船票推荐产品列表
     *
     * @return
     */
    @Override
    public List<ShipRecommendListDTO> queryRecommendList(TokenUser user) {
        //默认查询出发日期明天
        List<String> userIds = getUserIdsByUserId(user.getId());
        List<ShipRecommendListDTO> ShipRecommendListDTOList = shipProductMapper.selectShipRecommendList(LocalDate.now().plusDays(1), null);
        //辐加费-所有部门，均可见
        ShipRecommendListDTOList = ShipRecommendListDTOList.stream().filter(entity->{
            if(entity.getVisableType() == 3){
                return userIds.contains(String.valueOf(entity.getRelationId()));
            }
            return true;
        }).peek(entity->{
            //成本价*汇率+预订服务费+加辐费+税费
            BigDecimal afterPrice = entity.getCostPrice().multiply(entity.getExchangeRate()).add(entity.getServiceChargePrice()).add(entity.getTaxFee()).add(entity.getOtherFeePrice());
            entity.setPrice(afterPrice.setScale(2,BigDecimal.ROUND_HALF_UP));
        }).collect(Collectors.toList());

        return ShipRecommendListDTOList;
    }

    /**
     * 查询船票往返预订产品列表
     *
     * @param shipProductIsRecommendedRTReq
     * @return
     */
    @Override
    public List<ShipReserveRTListDTO> queryShipGoAndBackReserveList(ShipProductIsRecommendedRTReq shipProductIsRecommendedRTReq, TokenUser user) {
        List<ShipReserveRTListDTO> shipReserveRTList = new ArrayList<ShipReserveRTListDTO>();
        ShipReserveRTListDTO shipReserveRTListDTO = new ShipReserveRTListDTO();
        //先构造去程的参数
        ShipProductIsRecommendedReq shipProductIsRecommendedReq = new ShipProductIsRecommendedReq();
        shipProductIsRecommendedReq.setStartDate(shipProductIsRecommendedRTReq.getStartDate());
        shipProductIsRecommendedReq.setDepCityId(shipProductIsRecommendedRTReq.getDepCityId());
        shipProductIsRecommendedReq.setArrCityId(shipProductIsRecommendedRTReq.getArrCityId());
        shipProductIsRecommendedReq.setCabinClass(shipProductIsRecommendedRTReq.getCabinClass());
        shipProductIsRecommendedReq.setTicketNumber(shipProductIsRecommendedRTReq.getTicketNumber());
        shipReserveRTListDTO.setTripType(ShipConstants.SHIP_OW_TRIP_TYPE);
        List<String> userIds = getUserIdsByUserId(user.getId());
        shipReserveRTListDTO.setShipReserveList(queryReserveList(shipProductIsRecommendedReq, user,userIds));
        shipReserveRTList.add(shipReserveRTListDTO);

        shipReserveRTListDTO = new ShipReserveRTListDTO();
        shipProductIsRecommendedReq = new ShipProductIsRecommendedReq();
        shipProductIsRecommendedReq.setStartDate(shipProductIsRecommendedRTReq.getBackDate());
        shipProductIsRecommendedReq.setArrCityId(shipProductIsRecommendedRTReq.getDepCityId());
        shipProductIsRecommendedReq.setDepCityId(shipProductIsRecommendedRTReq.getArrCityId());
        shipProductIsRecommendedReq.setCabinClass(shipProductIsRecommendedRTReq.getCabinClass());
        shipProductIsRecommendedReq.setTicketNumber(shipProductIsRecommendedRTReq.getTicketNumber());
        shipReserveRTListDTO.setTripType(ShipConstants.SHIP_RT_TRIP_TYPE);
        shipReserveRTListDTO.setShipReserveList(queryReserveList(shipProductIsRecommendedReq, user,userIds));
        shipReserveRTList.add(shipReserveRTListDTO);

        return shipReserveRTList;
    }

    /**
     * 查询船票预订产品列表
     *
     * @param shipProductIsRecommendedReq
     * @return
     */
    @Override
    public List<ShipReserveListDTO> queryReserveList(ShipProductIsRecommendedReq shipProductIsRecommendedReq, TokenUser user,List<String> userIds) {
        //查询出所有的产品
        List<ShipReserveListDTO> shipReserveListDTOS = shipProductMapper.selectShipReserveList(shipProductIsRecommendedReq, userIds);
        for (ShipReserveListDTO shipReserveListDTO : shipReserveListDTOS) {
            //判断是加百分比还是加价格
            if (shipReserveListDTO.getAdjustType() == ShipConstants.ADJUST_TYPE_PERCENT) {
                double percent = shipReserveListDTO.getPercent();
                percent = percent * 0.01;
                //成本价*百分比+服务费+税费
                shipReserveListDTO.setPrice(shipReserveListDTO.getCosPrice().add(shipReserveListDTO.getCosPrice().multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP)));
                shipReserveListDTO.setPrice(shipReserveListDTO.getPrice().add(shipReserveListDTO.getServicePrice().add(shipReserveListDTO.getTaxPrice())));
            } else if (shipReserveListDTO.getAdjustType() == ShipConstants.ADJUST_TYPE_AMOUNT) {
                //价格 = 成本价+服务费+税费+加幅费
                shipReserveListDTO.setPrice(shipReserveListDTO.getPrice().add(shipReserveListDTO.getAmount()));
            }
            //查询产品自营集合
            List<ShipReserveDTO> shipReserveDTOS = shipProductMapper.selectOfflineSelfList(shipReserveListDTO.getId(), shipProductIsRecommendedReq.getStartDate());
            for (ShipReserveDTO shipReserveDTO : shipReserveDTOS) {
                //例如總庫存是20，最大可售數是10，此時取值10；當總庫存是20，最大可售數是30，此時取值20；
                if (shipReserveListDTO.getDailyStock() == null || shipReserveListDTO.getDailyStock() < shipReserveDTO.getLimitNum()) {
                    shipReserveDTO.setLimitNum(shipReserveListDTO.getDailyStock());
                }
                shipReserveDTO.setNumber(shipReserveDTO.getSoldNumber());
                shipReserveListDTO.setSoldNumber(shipReserveDTO.getSoldNumber());
                //判断是加百分比还是加价格
                if (shipReserveDTO.getAdjustType() == ShipConstants.ADJUST_TYPE_PERCENT) {
                    double percent = shipReserveDTO.getPercent();
                    percent = percent * 0.01;
                    //成本价*百分比+服务费+税费
                    shipReserveListDTO.setOffLinePrice(shipReserveListDTO.getCosPrice().multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP));
                    shipReserveDTO.setOffLinePrice(shipReserveListDTO.getOffLinePrice().add(shipReserveListDTO.getServicePrice().add(shipReserveListDTO.getTaxPrice())));
                } else if (shipReserveDTO.getAdjustType() == ShipConstants.ADJUST_TYPE_AMOUNT) {
                    //价格 = 成本价+服务费+税费+加幅费
                    shipReserveListDTO.setOffLinePrice(shipReserveDTO.getOffLinePrice());
                    shipReserveDTO.setOffLinePrice(shipReserveListDTO.getPrice().add(shipReserveDTO.getOffLinePrice()));
                }
            }
            shipReserveListDTO.setShipReserveList(shipReserveDTOS);
        }
        return shipReserveListDTOS;
    }

    @Override
    public List<ShipReserveListDTO> queryManualList(ShipProductManualReq shipProductManualReq) {
        return shipProductMapper.selectShipManual(shipProductManualReq);
    }


    @Override
    public ShipProductReservationSettingsDTO getShipProductReservationSettingsById(Long id) {
        ShipProductReservationSettings shipProductReservationSettings = shipProductReservationSettingsMapper.selectOne(
                new QueryWrapper<ShipProductReservationSettings>().lambda().eq(ShipProductReservationSettings::getShipProductId, id));
        ShipProductReservationSettingsDTO shipProductReservationSettingsDTO = new ShipProductReservationSettingsDTO();
        BeanUtils.copyProperties(shipProductReservationSettings, shipProductReservationSettingsDTO);
        return shipProductReservationSettingsDTO;
    }

    @Override
    public ShipProductChannelOfflineSelfCustomItemDTO queryOfflineSelfById(Long id) {
        QueryWrapper<ShipProductChannelOfflineSelfCustom> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipProductChannelOfflineSelfCustom::getOfflineId,id);
        ShipProductChannelOfflineSelfCustom shipProductChannelOfflineSelfCustom = shipProductChannelOfflineSelfCustomMapper.selectOne(queryWrapper);
        ShipProductChannelOfflineSelfCustomItemDTO shipProductChannelOfflineSelfCustomItemDTO = new ShipProductChannelOfflineSelfCustomItemDTO();
        BeanUtils.copyProperties(shipProductChannelOfflineSelfCustom, shipProductChannelOfflineSelfCustomItemDTO);
        return shipProductChannelOfflineSelfCustomItemDTO;
    }

    @Override
    public List<ShipProductCostAndDateListDTO> queryShipProductCostAndDateList(Long productId, LocalDate localDate, String userIds) {
        List<ShipProductCostAndDateListDTO> shipProductCostAndDateListDTOS = shipProductCostMapper.queryShipProductCostAndDateList2(productId, localDate, getUserIdsByUserId(Long.valueOf(userIds)));
        for (ShipProductCostAndDateListDTO shipProductCostAndDateListDTO : shipProductCostAndDateListDTOS) {
            //将币种转港币兑换率
            BigDecimal exchangeRate = shipProductCostAndDateListDTO == null ? BigDecimal.ZERO : mainDataCurrencyService.getExchangeRate(shipProductCostAndDateListDTO.getCurrencyName(),
                    CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);

            //HKD 转换成港币
            shipProductCostAndDateListDTO.setCostPrice(shipProductCostAndDateListDTO.getCostPrice() == null ? BigDecimal.ZERO : shipProductCostAndDateListDTO.getCostPrice()
                            .multiply(exchangeRate).add(shipProductCostAndDateListDTO.getServicePrice() == null ? BigDecimal.ZERO : shipProductCostAndDateListDTO.getServicePrice())
                    .add(shipProductCostAndDateListDTO.getTaxPrice() == null ? BigDecimal.ZERO : shipProductCostAndDateListDTO.getTaxPrice())
                    .add(Objects.isNull(shipProductCostAndDateListDTO.getAddFee())?BigDecimal.ZERO:shipProductCostAndDateListDTO.getAddFee()));
        }
        return shipProductCostAndDateListDTOS;
    }

    /**
     * 根据当前用户去查找对应的用户权限
     *
     * @param id
     * @return
     */
    private List<String> getUserIdsByUserId(Long id) {
        List<Long> longs = iSysDepartmentService.queryIdsByUserId(id);
        longs.add(id);
        String stringBuffer = "";
        for (Long aLong : longs) {
            stringBuffer += aLong.toString() + ",";
        }
        if (!"".equals(stringBuffer)) {
            stringBuffer = stringBuffer.substring(0, stringBuffer.length() - 1);
        }
        return Lists.newArrayList(stringBuffer.split(","));
    }

    @Override
    public List<ShipReserveDTO> queryOfflineSelfList(Long productId, LocalDate localDate) {
        return shipProductMapper.selectOfflineSelfList(productId, localDate);
    }

    @Override
    public ShipInitializationSettingsDTO queryShipInitializationSettings() {
        ShipInitializationSettingsDTO shipInitializationSettingsDTO = new ShipInitializationSettingsDTO();
        ShipInitializationSettings shipInitializationSettings = shipInitializationSettingsMapper.selectOne(Wrappers.<ShipInitializationSettings>lambdaQuery());
        BeanUtils.copyProperties(shipInitializationSettings, shipInitializationSettingsDTO);
        return shipInitializationSettingsDTO;
    }

    /**
     * 查询珠江接口单程票
     *
     * @param shipZJProductIsRecommendedReq
     * @return
     */
    @Override
    public List<ShipReserveListDTO> queryApiProductList(ShipZJProductIsRecommendedReq shipZJProductIsRecommendedReq) {
        List<ShipReserveListDTO> list = shipProductMapper.selectApiList(shipZJProductIsRecommendedReq);
        QueryWrapper<ShipInitializationSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipInitializationSettings::getIsDeleted, ShipConstants.NOT_DELETE);
        ShipInitializationSettings shipInitializationSettings = shipInitializationSettingsMapper.selectOne(queryWrapper);
        for (ShipReserveListDTO shipReserveListDTO : list) {
            BigDecimal totalAmount = new BigDecimal("0");
            //判断是加百分比还是加价格
            if (shipInitializationSettings.getBookingPriceType() == ShipConstants.ADJUST_TYPE_PERCENT) {
                double percent = shipInitializationSettings.getBookingPrice();
                percent = percent * 0.01;
                //成本价*百分比+服务费+税费
                totalAmount = totalAmount.add(shipReserveListDTO.getCosPrice().multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP));
            } else {
                totalAmount = totalAmount.add(new BigDecimal(shipInitializationSettings.getBookingPrice()));
            }
//            if (shipInitializationSettings.getRefundFeePriceType() == ShipConstants.ADJUST_TYPE_PERCENT) {
//                //价格 = 成本价+服务费+税费+加幅费
//                double percent = shipInitializationSettings.getRefundFeePrice();
//                percent = percent * 0.01;
//                totalAmount = totalAmount.add(shipReserveListDTO.getCosPrice().multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP));
//            } else {
//                totalAmount = totalAmount.add(new BigDecimal(shipInitializationSettings.getRefundFeePrice()));
//            }
            shipReserveListDTO.setCosPrice(shipReserveListDTO.getCosPrice().add(totalAmount));
        }
        return list;
    }

    @Override
    public List<ShipApiProductTypeListDTO> queryApiProductGoAndBackList(ShipZJProductApiReq shipZJProductApiReq, TokenUser user) {
        return zJShipProductService.queryVoyage(shipZJProductApiReq);
    }

    @Override
    public List<ShipReserveListDTO> queryApiProductList(String productId, int ticketNumber) {
        ShipZJProductIsRecommendedReq shipZJProductIsRecommendedReq = new ShipZJProductIsRecommendedReq();
        shipZJProductIsRecommendedReq.setProductId(productId);
        shipZJProductIsRecommendedReq.setTicketNumber(ticketNumber);
        return shipProductMapper.selectApiList(shipZJProductIsRecommendedReq);
    }

    @Override
    public Result saveShipBooking(ShipProductReq shipProductReq, TokenUser user) {
        List<String> productIds = shipProductReq.getProductIds();
        for (String productId : productIds) {

            QueryWrapper<ShipProductReservationSettings> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(ShipProductReservationSettings::getShipProductId, productId);
            ShipProductReservationSettings shipProductReservationSettings1 = shipProductReservationSettingsMapper.selectOne(wrapper);

            ShipProductReservationSettingsReq hipProductReservationSettingsReq = shipProductReq.getShipProductReservationSettings();
            ShipProductReservationSettings shipProductReservationSettings = new ShipProductReservationSettings();
            BeanUtils.copyProperties(hipProductReservationSettingsReq, shipProductReservationSettings);
            if (null != shipProductReservationSettings1) {
                BeanUtils.copyProperties(hipProductReservationSettingsReq, shipProductReservationSettings1);
                shipProductReservationSettings.setRefundFeePrice(hipProductReservationSettingsReq.getRefundFeePrice() != null ?
                        hipProductReservationSettingsReq.getRefundFeePrice().doubleValue() : null);
                shipProductReservationSettings.setModifiedId(user.getId());
                shipProductReservationSettings.setGmtModified(LocalDateTime.now());
                shipProductReservationSettingsMapper.updateById(shipProductReservationSettings1);
            } else {
                shipProductReservationSettings.setId(SnowflakeIdWorker.nextId());
                shipProductReservationSettings.setShipProductId(Long.valueOf(productId));
                shipProductReservationSettings.setRefundFeePrice(hipProductReservationSettingsReq.getRefundFeePrice() != null ?
                        hipProductReservationSettingsReq.getRefundFeePrice().doubleValue() : null);
                shipProductReservationSettings.setCreateId(user.getId());
                shipProductReservationSettings.setGmtCreate(LocalDateTime.now());
                shipProductReservationSettingsMapper.insert(shipProductReservationSettings);
            }
        }
        return Result.success(productIds);
    }

    /**
     * 修改审核通过信德船票产品
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result updateApprovedXDShipProduct(ShipProductReq shipProductReq, TokenUser user) {
        ShipProduct shipProduct = shipProductMapper.selectById(shipProductReq.getId());

        shipProduct.setApplicableCrowdId(shipProductReq.getApplicableCrowdId());
        shipProduct.setApplicableCrowdName(shipProductReq.getApplicableCrowdName());
        shipProduct.setPackStatus(shipProductReq.getPackStatus());
        //审批状态（1 待提交，2 待审批，3 审批中，4 审批不通过，5 审批通过）
        shipProduct.setApprovalStatus(2);
        shipProduct.setGmtModified(LocalDateTime.now());
        shipProduct.setModifiedId(user.getId());
        shipProductMapper.updateById(shipProduct);

        this.deleteShipCosts(shipProductReq);
        this.saveShipProductCostsInfo(shipProductReq, user);
        return Result.success();
    }

    /**
     * 根据产品编号
     *
     * @param shipProductReq
     */
    private void deleteShipCosts(ShipProductReq shipProductReq) {
        List<ShipProductCost> shipProductCosts = shipProductCostMapper.selectList(
                new QueryWrapper<ShipProductCost>().lambda().eq(ShipProductCost::getShipProductId, shipProductReq.getId()));
        for (ShipProductCost shipProductCost : shipProductCosts) {
            Long id = shipProductCost.getId();
            shipProductCostTouristMapper.delete(
                    new QueryWrapper<ShipProductCostTourist>().lambda().eq(ShipProductCostTourist::getCostId, id));
            shipProductCostDateMapper.delete(
                    new QueryWrapper<ShipProductCostDate>().lambda().eq(ShipProductCostDate::getCostId, id)
            );
        }
        //再删除成本
        shipProductCostMapper.delete(new QueryWrapper<ShipProductCost>().lambda().eq(ShipProductCost::getShipProductId, shipProductReq.getId()));
    }

    /**
     * 修改审核通过珠江船票产品
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result updateApprovedZJShipProduct(ShipProductReq shipProductReq, TokenUser user) {

        ShipProduct shipProduct = shipProductMapper.selectById(shipProductReq.getId());

        shipProduct.setAvailableSeat(shipProductReq.getAvailableSeat());
        //审批状态（1 待提交，2 待审批，3 审批中，4 审批不通过，5 审批通过）
        shipProduct.setApprovalStatus(2);
        shipProduct.setApplicableCrowdId(shipProductReq.getApplicableCrowdId());
        shipProduct.setApplicableCrowdName(shipProductReq.getApplicableCrowdName());
        shipProduct.setPackStatus(shipProductReq.getPackStatus());
        shipProduct.setGmtModified(LocalDateTime.now());
        shipProduct.setModifiedId(user.getId());
        shipProductMapper.updateById(shipProduct);


        return Result.success();
    }

    /**
     * 修改审核不通过船票产品
     *
     * @param shipProductReq
     * @param user
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result updateUnapprovedShipProduct(ShipProductReq shipProductReq, TokenUser user) {
        Result checkResult = checkShipProductExist(shipProductReq, user);
        if (!Objects.isNull(checkResult)) {
            return checkResult;
        }
        Result checkDateResult = checkCostDateRepeat(shipProductReq.getShipProductCostReqList());
        if (!Objects.isNull(checkDateResult)) {
            return checkDateResult;
        }
        //审核不通过修改 等同于新增(必须先删后新增)
        shipProductMapper.deleteById(shipProductReq.getId());
        this.deleteShipCosts(shipProductReq);

        //审核不通过的产品 调用新增方法
        return this.saveShipProductInfo(shipProductReq, user);

    }
    @Autowired
    private MainDataShipCompanyMapper mainDataShipCompanyMapper;

    @Override
    public ShipProductViewDetailDTO queryProductDetail(Long id) {

        //产品基本信息
        ShipProduct shipProduct = shipProductMapper.selectById(id);

        ShipProductViewDetailDTO shipProductViewDetailDTO = new ShipProductViewDetailDTO();

        BeanUtils.copyProperties(shipProduct, shipProductViewDetailDTO);
        if(shipProduct != null ){
            QueryWrapper<MainDataShipCompany> companyQueryWrapper = new QueryWrapper<>();
            companyQueryWrapper.lambda().eq(MainDataShipCompany::getType,shipProduct.getCompanyType());
            MainDataShipCompany mainDataShipCompany = mainDataShipCompanyMapper.selectOne(companyQueryWrapper);
            shipProductViewDetailDTO.setCompanyTypeDesc(mainDataShipCompany.getContent());
            shipProductViewDetailDTO.setCompanyType(mainDataShipCompany.getType());
        }

        if(shipProduct.getRouteId() != null){
            ShipRoutePageReq shipRoutePageReq = new ShipRoutePageReq();
            shipRoutePageReq.setId(shipProduct.getRouteId());
            Result<ShipRouteDTO> shipRouteDTOResult = iShipRouteService.queryShipRouteDetail(shipRoutePageReq);
            ShipRouteDTO data = shipRouteDTOResult.getData();

            shipProductViewDetailDTO.setStartPlace(data != null ? data.getDepPlaceName() :"");
            shipProductViewDetailDTO.setEndPlace(data != null ? data.getArrPlaceName() :"");
            shipProductViewDetailDTO.setSeatNumbers(data != null ? data.getSeatNumbers() :"");
        }
        List<ShipProductCostDTO> shipProductCost = shipProductCostMapper.getShipProductCost(id);

        //产品成本
        shipProductViewDetailDTO.setShipProductCostReqList(getShipProductCostList(shipProductViewDetailDTO,shipProductCost,shipProduct.getAvailableSeat()));

        //产品设置
        QueryWrapper<ShipProductReservationSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipProductReservationSettings::getShipProductId,id);
        ShipProductReservationSettings shipProductReservationSettings =  shipProductReservationSettingsMapper.selectOne(queryWrapper);
        if(shipProductReservationSettings != null){
            ShipProductReservationSettingsDTO shipProductReservationSettingsDTO = new ShipProductReservationSettingsDTO();
            BeanUtils.copyProperties(shipProductReservationSettings, shipProductReservationSettingsDTO);
            shipProductViewDetailDTO.setShipProductReservationSettings(shipProductReservationSettingsDTO);
        }
        return shipProductViewDetailDTO;
    }

    private List<ShipProductCostDTO> getShipProductCostList(ShipProductViewDetailDTO shipProductViewDetailDTO, List<ShipProductCostDTO> shipProductCost, String availableSeat) {
        //一个shipProductCost对象里面存在一个成本日期集合 一个成本日期里面存在多个成本设置
        for (ShipProductCostDTO shipProductCostDTO : shipProductCost) {
            //根据成本ID获取成本设置日期集合
            List<ShipProductCostDate> shipProductCostDates = shipProductCostDateMapper.selectList(
                    new QueryWrapper<ShipProductCostDate>().lambda().in(ShipProductCostDate::getCostId, shipProductCostDTO.getId())
            );
            List<ShipProductCostDateDTO> shipProductCostDateDTOList = new ArrayList<>();
            for (ShipProductCostDate shipProductCostDate : shipProductCostDates) {
                ShipProductCostDateDTO dto = new ShipProductCostDateDTO();
                BeanUtils.copyProperties(shipProductCostDate, dto);
                shipProductCostDateDTOList.add(dto);
            }
            shipProductCostDTO.setShipProductCostDateList(shipProductCostDateDTOList);
            List<ShipProductCostTourist> shipProductCostTourists = shipProductCostTouristMapper.selectList(
                    new QueryWrapper<ShipProductCostTourist>().lambda().in(ShipProductCostTourist::getCostId, shipProductCostDTO.getId())
            );
            List<ShipProductCostTouristDTO> shipProductCostTouristDTO = new ArrayList<>();
            for (ShipProductCostTourist shipProductCostTourist : shipProductCostTourists) {
                ShipProductCostTouristDTO dto = new ShipProductCostTouristDTO();
                BeanUtils.copyProperties(shipProductCostTourist, dto);
                shipProductCostTouristDTO.add(dto);
            }
            shipProductCostDTO.setShipProductCostTouristList(shipProductCostTouristDTO);

            //每日库存 座位可选，则以座位数为每日库存数
            if(shipProductViewDetailDTO != null && !StringUtils.isEmpty(availableSeat)){
                String[] split = availableSeat.split(",");
                shipProductCostDTO.setDailyStock(split.length + "");
            }
        }

        //每日库存 座位可选，则以座位数为每日库存数
        if(!StringUtils.isEmpty(availableSeat)){
            String[] split = availableSeat.split(",");
            shipProductViewDetailDTO.setStock(split.length);
        }
        return shipProductCost;
    }

    @Override
    public PageResponse<ShipProductDTO> queryList(ShipProductPageReq shipProductPageReq,TokenUser tokenUser) {
        //不是管理员
        List<Long> data = Lists.newArrayListWithCapacity(5);
//        if (!GlobalConstants.Role.isAdmin(tokenUser.getUsername())) {
//            if (shipProductPageReq.getMenuId() == null) {
//                throw new BusinessException(SystemError.SYSTEM_2106);
//            }
//            Result<List<Long>> permissionResult = sysPermissionService.queryPermission(shipProductPageReq.getMenuId(), tokenUser.getId());
//            if (!permissionResult.isSuccess()) {
//                SystemError result = SystemError.getDefined(permissionResult.getCode());
//                throw new BusinessException(result);
//            }
//            data.addAll(permissionResult.getData()) ;
//        }

        //创建人、负责人有权限
        PageResponse<ShipProductDTO> result = null;
        IPage<ShipProductDTO> agentPage = new Page<>(shipProductPageReq.getPageNo(), shipProductPageReq.getPageSize());
        agentPage = shipProductMapper.queryList(shipProductPageReq, agentPage,data);
        List<ShipProductDTO> records = agentPage.getRecords();
        ProcessorUtil.processMore(records,ShipProductDTO.class);
        result = new PageResponse<>(records, agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    @Override
    public ShipProductDetailDTO queryDetail(Long id) {
        ShipProductDetailDTO shipProductDetailDTO = null;
        shipProductDetailDTO = shipProductMapper.queryDetail(id);
        List<ShipProductCostDTO> shipProductCost = shipProductCostMapper.getShipProductCost(id);
        shipProductCost = getShipProductCostList(null, shipProductCost, shipProductDetailDTO.getAvailableSeat());
        for (ShipProductCostDTO shipProductCostDTO : shipProductCost) {
            //把产品的座位赋值给成本中心里面的座位
            shipProductCostDTO.setAvailableSeat(shipProductDetailDTO.getAvailableSeat());
        }
        shipProductDetailDTO.setShipProductCostList(shipProductCost);
        ProcessorUtil.process(shipProductDetailDTO,ShipProductDetailDTO.class);
        return shipProductDetailDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result saveShipProduct(ShipProductReq shipProductReq, TokenUser user) {

        //審批通過
        if(ApprovalStatus.REVIEW_YES.getCode().equals(shipProductReq.getApprovalStatus())){
            if(shipProductReq.getProductSource() == 1){
                return updateApprovedXDShipProduct(shipProductReq,user);
            }else {
                return updateApprovedZJShipProduct(shipProductReq,user);
            }
        }
        //其他
        else {
            Result checkResult = checkShipProductExist(shipProductReq, user);
            if (!Objects.isNull(checkResult)) {
                return checkResult;
            }
            Result checkDateResult = checkCostDateRepeat(shipProductReq.getShipProductCostReqList());
            if (!Objects.isNull(checkDateResult)) {
                return checkDateResult;
            }
            return saveShipProductInfo(shipProductReq, user);
        }
    }

    private Result saveShipProductInfo(ShipProductReq shipProductReq, TokenUser user) {
        String productCode = buildProductNumber(user.getId(), LocalDateTime.now());
        //获取船种、航次码、开船时间、到达时间的集合 循环插入数据
        List<String> productIds = new ArrayList<>();
        List<ShipTypeProductList> shipTypeProductList = shipProductReq.getShipTypeProductList();
        List<String> productIds1 = shipProductReq.getProductIds();

        if (null != productIds1) {
            List<Long> ids = productIds1.stream().map(id -> Long.valueOf(id)).collect(Collectors.toList());
            shipProductMapper.deleteBatchIds(ids);
            List<ShipProductCost> shipProductCosts = shipProductCostMapper.selectList(new QueryWrapper<ShipProductCost>().lambda().in(ShipProductCost::getShipProductId, ids));
            List<Long> collect = shipProductCosts.stream().map(ShipProductCost::getId).collect(Collectors.toList());
            shipProductCostTouristMapper.delete(new QueryWrapper<ShipProductCostTourist>().lambda().in(ShipProductCostTourist::getCostId, collect));
            shipProductCostDateMapper.delete(new QueryWrapper<ShipProductCostDate>().lambda().in(ShipProductCostDate::getCostId, collect));
        }

        //新增产品ID集合
        List<Long> insertProductIds = Lists.newArrayListWithExpectedSize(5);
        //如果的编辑，保证不允许添加多个船次
        for (int i = 0; i < shipTypeProductList.size(); i++) {
            ShipTypeProductList shipTypeItem = shipTypeProductList.get(i);
            //保存船票产品信息
            ShipProduct shipProduct = new ShipProduct();
            BeanUtils.copyProperties(shipProductReq, shipProduct);
            //船产品ID
            Long shipProductId = SnowflakeIdWorker.nextId();
            insertProductIds.add(shipProductId);
            productIds.add(shipProductId.toString());
            //成本ID
            Long shipProductCostId = null;
            //负责人ID
            Long chargeUserId = shipProduct.getChargeUserId();
            shipProduct.setShipTypeId(shipTypeItem.getShipTypeId());
            shipProduct.setShipTypeName(shipTypeItem.getShipTypeName());
            shipProduct.setVoyage(shipTypeItem.getVoyage());
            shipProduct.setDepTime(shipTypeItem.getDepTime());
            shipProduct.setArrTime(shipTypeItem.getArrTime());
            shipProduct.setCabinClassName(shipProductReq.getCabinClassName());

            //手工产品
            shipProduct.setProductSource(1);
            shipProduct.setId(shipProductId);
            //产品编码
            shipProduct.setCode(productCode);
            //审批状态（1 待提交，2审批中，4 审批不通过，3 审批通过）
            shipProduct.setApprovalStatus(ApprovalStatus.WAIT_SUBMIT.getCode());
            //上架设置默认为不上架
            shipProduct.setShelvesStatus(ShipConstants.UN_SHELVES);
            shipProduct.setGmtCreate(LocalDateTime.now());
            shipProduct.setIsDeleted(ShipConstants.NOT_DELETE);
            //如果页面没有填写负责人,则默认当前账号
            if (StringUtils.isEmpty(shipProduct.getChargeUserId())) {
                shipProduct.setChargeUserId(user.getId());
                chargeUserId = user.getId();
            }
            shipProductMapper.insert(shipProduct);

            //保存成本数据
            List<ShipProductCostReq> shipProductCostReq = shipProductReq.getShipProductCostReqList();
            for (ShipProductCostReq shipProductCostItem : shipProductCostReq) {
                ShipProductCost shipProductCost = new ShipProductCost();
                BeanUtils.copyProperties(shipProductCostItem, shipProductCost);
                shipProductCostId = SnowflakeIdWorker.nextId();
                shipProductCost.setId(shipProductCostId);
                //关联船票
                shipProductCost.setShipProductId(shipProductId);
                shipProductCost.setCreateId(chargeUserId);
                shipProductCost.setIsDeleted(ShipConstants.NOT_DELETE);
                shipProductCost.setGmtCreate(LocalDateTime.now());
                shipProductCostMapper.insert(shipProductCost);

                //保存设置成本价
                for (ShipProductCostTouristReq shipProductCostTouristReq : shipProductCostItem.getShipProductCostTouristList()) {
                    ShipProductCostTourist shipProductCostTourist = new ShipProductCostTourist();
                    BeanUtils.copyProperties(shipProductCostTouristReq, shipProductCostTourist);
                    //关联成本ID
                    shipProductCostTourist.setCostId(shipProductCostId);
                    shipProductCostTourist.setGmtCreate(LocalDateTime.now());
                    shipProductCostTourist.setIsDeleted(ShipConstants.NOT_DELETE);
                    shipProductCostTourist.setCreateId(chargeUserId);
                    shipProductCostTouristMapper.insert(shipProductCostTourist);
                }

                //保存成本有效日期集合
                List<ShipProductCostDateReq> shipProductCostDateReqList = shipProductCostItem.getShipProductCostDateList();
                for (ShipProductCostDateReq ShipProductCostDateReq : shipProductCostDateReqList) {
                    ShipProductCostDate shipProductCostDate = new ShipProductCostDate();
                    BeanUtils.copyProperties(ShipProductCostDateReq, shipProductCostDate);
                    shipProductCostDate.setId(SnowflakeIdWorker.nextId());
                    //关联成本ID
                    shipProductCostDate.setCostId(shipProductCostId);
                    shipProductCostDate.setCreateId(chargeUserId);
                    shipProductCostDate.setDailyStock(ShipProductCostDateReq.getDailyStock());
                    shipProductCostDate.setIsDeleted(ShipConstants.NOT_DELETE);
                    shipProductCostDate.setDateBegin(DateUtil.toLocalDateTime(ShipProductCostDateReq.getDateBegin()));
                    shipProductCostDate.setDateEnd(DateUtil.toLocalDateTime(ShipProductCostDateReq.getDateEnd()));
                    shipProductCostDate.setGmtCreate(LocalDateTime.now());
                    shipProductCostDateMapper.insert(shipProductCostDate);
                }
            }
        }

        //更新产品设置与新增产品的关联
        if (null != productIds1) {
            List<Long> ids = productIds1.stream().map(id -> Long.valueOf(id)).collect(Collectors.toList());
            List<ShipProductReservationSettings> shipProductReservationSettings = shipProductReservationSettingsMapper.
                    selectList(new QueryWrapper<ShipProductReservationSettings>().lambda().in(ShipProductReservationSettings::getShipProductId, ids));

            if(CollectionUtils.isNotEmpty(shipProductReservationSettings)){
                AtomicInteger count = new AtomicInteger(0);
                shipProductReservationSettings.forEach(entity->{
                    entity.setShipProductId(insertProductIds.get(count.getAndIncrement()));
                    shipProductReservationSettingsMapper.updateById(entity);
                });
            }
        }
        return Result.success(productIds);
    }

    private void saveShipProductCostsInfo(ShipProductReq shipProductReq, TokenUser user) {
        List<ShipProductCostReq> shipProductCostReq = shipProductReq.getShipProductCostReqList();
        Long chargeUserId = shipProductReq.getChargeUserId();
        //船产品ID
        long shipProductId = shipProductReq.getId();
        if (StringUtils.isEmpty(shipProductReq.getChargeUserId())) {
            chargeUserId = user.getId();
        }
        for (ShipProductCostReq shipProductCostItem : shipProductCostReq) {
            ShipProductCost shipProductCost = new ShipProductCost();
            BeanUtils.copyProperties(shipProductCostItem, shipProductCost);
            Long shipProductCostId = SnowflakeIdWorker.nextId();
            shipProductCost.setId(shipProductCostId);
            //关联船票
            shipProductCost.setShipProductId(shipProductId);
            shipProductCost.setCreateId(chargeUserId);
            shipProductCost.setIsDeleted(ShipConstants.NOT_DELETE);
            shipProductCost.setGmtCreate(LocalDateTime.now());
            shipProductCostMapper.insert(shipProductCost);

            //保存设置成本价
            for (ShipProductCostTouristReq shipProductCostTouristReq : shipProductCostItem.getShipProductCostTouristList()) {
                ShipProductCostTourist shipProductCostTourist = new ShipProductCostTourist();
                BeanUtils.copyProperties(shipProductCostTouristReq, shipProductCostTourist);
                //关联成本ID
                shipProductCostTourist.setCostId(shipProductCostId);
                shipProductCostTourist.setGmtCreate(LocalDateTime.now());
                shipProductCostTourist.setIsDeleted(ShipConstants.NOT_DELETE);
                shipProductCostTourist.setCreateId(chargeUserId);
                shipProductCostTouristMapper.insert(shipProductCostTourist);
            }

            //保存成本有效日期集合
            List<ShipProductCostDateReq> shipProductCostDateReqList = shipProductCostItem.getShipProductCostDateList();
            for (ShipProductCostDateReq ShipProductCostDateReq : shipProductCostDateReqList) {
                ShipProductCostDate shipProductCostDate = new ShipProductCostDate();
                BeanUtils.copyProperties(ShipProductCostDateReq, shipProductCostDate);
                shipProductCostDate.setId(SnowflakeIdWorker.nextId());
                //关联成本ID
                shipProductCostDate.setCostId(shipProductCostId);
                shipProductCostDate.setCreateId(chargeUserId);
                shipProductCostDate.setIsDeleted(ShipConstants.NOT_DELETE);
                shipProductCostDate.setGmtCreate(LocalDateTime.now());
                shipProductCostDateMapper.insert(shipProductCostDate);
            }
        }
    }

    /**
     * 校验規則，航線+艙位+班次碼+供應商不能重複存在
     * 校验規則，校验開船时间和船种名称和航次码是否重复
     *
     * @param shipProductReq
     * @return null else return error
     */
    private Result<Object> checkShipProductExist(ShipProductReq shipProductReq, TokenUser user) {
        if (null == user) {
            return Result.failed(SystemError.USER_1000);
        }
        if (null == shipProductReq) {
            return Result.failed(SystemError.SHIP_PRODUCT_11002);
        }

        //如果的編輯自身，不需要做校驗
        if(CollectionUtils.isNotEmpty(shipProductReq.getProductIds())){
            return null;
        }
        ShipProduct shipProduct = new ShipProduct();
        BeanUtils.copyProperties(shipProductReq, shipProduct);
        List<ShipTypeProductList> shipTypeProductList = shipProductReq.getShipTypeProductList();
        Map<String, String> map = new HashMap<>();
        for (ShipTypeProductList typeProductList : shipTypeProductList) {
            String bufferKey = "";
            QueryWrapper<ShipProduct> queryWrapper = new QueryWrapper<>();
            //航线ID
            queryWrapper.eq("route_id", shipProductReq.getRouteId());
            //航次码
            queryWrapper.eq("voyage", typeProductList.getVoyage());
            //船舱等级
            queryWrapper.eq("cabin_class", shipProductReq.getCabinClass());
            //供应商ID
            queryWrapper.eq("supplier_id", shipProductReq.getSupplierId());
            //出发时间
            queryWrapper.eq("dep_time", typeProductList.getDepTime());
            if (0 != shipProductMapper.selectCount(queryWrapper)) {
                return Result.failed(SystemError.SHIP_PRODUCT_11001);
            }
            //校验開船时间和船种名称和航次码是否重复
            bufferKey += typeProductList.getRouteName() + typeProductList.getVoyage() + typeProductList.getDepTime();
            if (map.containsKey(bufferKey)) {
                return Result.failed(SystemError.SHIP_PRODUCT_11004);
            } else {
                map.put(bufferKey, bufferKey);
            }
        }
        return null;
    }


    /**
     * 产品成本日期校验
     *
     * @param shipProductCostReqList
     * @return
     */
    private Result<Object> checkCostDateRepeat(List<ShipProductCostReq> shipProductCostReqList) {
        List<ShipProductCostDateReq> shipProductCostDateReqList = new ArrayList<>();
        for (int i = 0; i < shipProductCostReqList.size(); i++) {
            shipProductCostDateReqList.addAll(shipProductCostReqList.get(i).getShipProductCostDateList());
        }
        for (int i = 0; i < shipProductCostDateReqList.size(); i++) {
            ShipProductCostDateReq shipProductCostDateReq = shipProductCostDateReqList.get(i);
            if (shipProductCostDateReq.getDateBegin().isBefore(LocalDate.now())) {
                // 船票产品加幅策略保存，开始日期不能小于当前日期校验
                return Result.failed(SystemError.SHIP_PRODUCT_11019);
            }
            if (i == 0 && shipProductCostDateReq.getDateBegin().isAfter(shipProductCostDateReq.getDateEnd())) {
                // 开始日期必须小于结束日期校验
                return Result.failed(SystemError.SHIP_PRODUCT_11020);
            }
            for (int j = 0; j < shipProductCostDateReqList.size(); j++) {
                ShipProductCostDateReq shipProductCostDateReq1 = shipProductCostDateReqList.get(j);
                if (i >= j) { // 自身和已经校验过的跳过日期校验
                    continue;
                }
                if (i == 0 && shipProductCostDateReq1.getDateBegin().isAfter(shipProductCostDateReq1.getDateEnd())) {
                    // 开始日期必须小于结束日期校验
                    return Result.failed(SystemError.SHIP_PRODUCT_11019);
                }
                if (DateUtil.isDateRange(shipProductCostDateReq.getDateBegin(), shipProductCostDateReq.getDateEnd(), shipProductCostDateReq1.getDateBegin(), shipProductCostDateReq1.getDateEnd())) {
                    // 当前日期与其他日期区域重叠校验
                    return Result.failed(SystemError.SHIP_PRODUCT_11021);
                }
                if (i == 0 && shipProductCostDateReq1.getDateBegin().isAfter(shipProductCostDateReq1.getDateEnd())) {
                    // 开始日期必须小于结束日期校验
                    return Result.failed(SystemError.SHIP_PRODUCT_11019);
                }
                if (DateUtil.isDateRange(shipProductCostDateReq.getDateBegin(), shipProductCostDateReq.getDateEnd(), shipProductCostDateReq1.getDateBegin(), shipProductCostDateReq1.getDateEnd())) {
                    // 当前日期与其他日期区域重叠校验
                    return Result.failed(SystemError.SHIP_PRODUCT_11021);
                }
            }
        }
        return null;
    }


    /**
     * PC+員工編號+月日4位+時分4位+4位隨機數字
     *
     * @param userId
     * @return
     */
    private String buildProductNumber(Long userId, LocalDateTime nowLocalDateTime) {
        UserDTO userDTO = sysUserService.loadUserByParam(userId, 1);
        String employeeNumber = userDTO.getEmployeeNumber();
        String monthCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMonthValue()), 2, "0");
        String dayCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getDayOfMonth()), 2, "0");
        String hourCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("PC").append(employeeNumber).append(monthCode).append(dayCode).append(hourCode).append(minuteCode).append(randomNumber);
        return orderNumberSb.toString();
    }


}
